/*
 * XSLTComponent.java
 *
 * Created on July 31, 2006, 12:50 AM
 *
 * (C) R. Alexander Milowski alex@milowski.com
 */

package org.infoset.xml.jaxp;

import java.net.URI;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamSource;
import org.infoset.xml.Document;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.Item;
import org.infoset.xml.Item.ItemType;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.infoset.xml.dom.DOMDocumentProxy;
import org.infoset.xml.filter.*;
import org.infoset.xml.sax.SAXEventGenerator;
import org.infoset.xml.sax.SAXItemDestination;

/**
 *
 * @author R. Alexander Milowski
 */
public class SAXTransformerSourceFilter implements ItemFilter {
   
   static Logger LOG = Logger.getLogger(SAXTransformerSourceFilter.class.getName());
   SAXTransformerFactory factory;
   TransformerHandler transformer;
   ItemDestination sink;
   SAXItemDestination saxSink;
   
   /** Creates a new instance of XSLTComponent */
   public SAXTransformerSourceFilter() {
      this.factory = (SAXTransformerFactory)TransformerFactory.newInstance();
      saxSink = null;
      transformer = null;
   }
   
   public SAXTransformerSourceFilter(SAXTransformerFactory factory) {
      this.factory = factory;
      saxSink = null;
      transformer = null;
   }
   
   public void loadTransform(URL location) 
      throws XMLException
   {
      try {
         transformer = factory.newTransformerHandler(new StreamSource(location.toString()));
      } catch (TransformerConfigurationException ex) {
         throw new XMLException("Cannot load transform.",ex);
      }
   }
   
   public void loadTransform(Document xformDocument) 
      throws XMLException
   {
      try {
         // Use a W3C DOM proxy to guarantee the transformer factory can handle it
         DOMDocumentProxy proxy = new DOMDocumentProxy(xformDocument);
         DOMSource source = new DOMSource(proxy);

         // Set the base URI if it is present
         URI baseURI = xformDocument.getBaseURI();
         if (baseURI!=null) {
            source.setSystemId(baseURI.toString());
         }

         // Load the transformer
         transformer = factory.newTransformerHandler(source);
      } catch (TransformerConfigurationException ex) {
         throw new XMLException("Cannot load transform.",ex);
      }
   }
   
   public void setParameter(Name name,Object value) {
      if (transformer==null) {
         throw new IllegalStateException("No transformation has been specified.");
      }
      Transformer xform = transformer.getTransformer();
      xform.setParameter(name.getLocalName(),value);
   }
   
   public void attach(ItemDestination sink) {
      this.sink = sink;
   }
   
   public void send(Item item) 
      throws XMLException
   {
      if (item.getType()==ItemType.DocumentItem) {
         if (transformer==null) {
            throw new IllegalStateException("No transformation has been specified.");
         }

         saxSink = new SAXItemDestination(transformer);

         SAXEventGenerator generator = new SAXEventGenerator();
         generator.setItemConstructor(InfosetFactory.getDefaultInfoset().createItemConstructor());
         if (LOG.isLoggable(Level.FINEST)) {
            generator.setItemDestination(new ItemDestination() {
               public void send(Item item)
                  throws XMLException {
                  LOG.info(item.toString());
                  sink.send(item);
               }
            });
         } else {
            generator.setItemDestination(sink);
         }
         transformer.setResult(new SAXResult(generator));
      } else if (saxSink==null) {
         throw new IllegalStateException("No document item was send before item type "+item.getType());
      }
      saxSink.send(item);
   }
   
}
